{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "7feab02d",
   "metadata": {},
   "source": [
    "# EnumOutputParser\n",
    "\n",
    "- Author: [ranian963](https://github.com/ranian963)\n",
    "- Peer Review : [JaeHo Kim](https://github.com/Jae-hoya)\n",
    "- Proofread : [Two-Jay](https://github.com/Two-Jay)\n",
    "- This is a part of [LangChain Open Tutorial](https://github.com/LangChain-OpenTutorial/LangChain-OpenTutorial)\n",
    "\n",
    "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/LangChain-OpenTutorial/LangChain-OpenTutorial/blob/main/03-OutputParser/07-EnumOutputParser.ipynb)[![Open in GitHub](https://img.shields.io/badge/Open%20in%20GitHub-181717?style=flat-square&logo=github&logoColor=white)](https://github.com/LangChain-OpenTutorial/LangChain-OpenTutorial/blob/main/03-OutputParser/07-EnumOutputParser.ipynb)\n",
    "## Overview\n",
    "In this tutorial, we introduce how to use ```EnumOutputParser``` to **extract valid Enum values** from the output of an LLM.\n",
    "\n",
    "```EnumOutputParser``` is a tool that parses the output of a language model into **one of the predefined enumeration (Enum) values** , offering the following features:\n",
    "\n",
    "- Enumeration Parsing: Converts the string output into a predefined ```Enum``` value.\n",
    "- Type Safety: Ensures that the parsed result is always one of the defined ```Enum``` values.\n",
    "- Flexibility: Automatically handles spaces and line breaks."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2bb70703",
   "metadata": {},
   "source": [
    "### Table of Contents\n",
    "\n",
    "- [Overview](#overview)\n",
    "- [Environment Setup](#environment-setup)\n",
    "- [Introduction to EnumOutputParser](#introduction-to-enumoutputparser)\n",
    "- [Example: Colors Enum Parser](#example-colors-enum-parser)\n",
    "\n",
    "### References\n",
    "\n",
    "- [LangChain: Output Parsers](https://python.langchain.com/docs/concepts/output_parsers/)\n",
    "- [LangChain: EnumOutputParser](https://python.langchain.com/api_reference/langchain/output_parsers/langchain.output_parsers.enum.EnumOutputParser.html#langchain.output_parsers.enum.EnumOutputParser)\n",
    "- [Enum in Python](https://docs.python.org/3/library/enum.html)\n",
    "- [LangChain Open Tutorial](https://github.com/LangChain-OpenTutorial/LangChain-OpenTutorial)\n",
    "----"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "de94921e",
   "metadata": {},
   "source": [
    "## Environment Setup\n",
    "\n",
    "Set up the environment. You may refer to [Environment Setup](https://wikidocs.net/257836) for more details.\n",
    "\n",
    "**[Note]**\n",
    "- ```langchain-opentutorial``` is a package that provides a set of easy-to-use environment setup, useful functions and utilities for tutorials. \n",
    "- You can checkout the [```langchain-opentutorial```](https://github.com/LangChain-OpenTutorial/langchain-opentutorial-pypi) for more details."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "846712b5",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%capture --no-stderr\n",
    "%pip install langchain-opentutorial"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "33859c1a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Installing required libraries\n",
    "from langchain_opentutorial import package\n",
    "\n",
    "package.install(\n",
    "    [\n",
    "        \"langsmith\",\n",
    "        \"langchain\",\n",
    "        \"langchain_openai\"\n",
    "    ],\n",
    "    verbose=False,\n",
    "    upgrade=False,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1c6b38d7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Set environment variables\n",
    "from langchain_opentutorial import set_env\n",
    "\n",
    "set_env(\n",
    "    {\n",
    "        \"OPENAI_API_KEY\": \"\",\n",
    "        \"LANGCHAIN_API_KEY\": \"\",\n",
    "        \"LANGCHAIN_TRACING_V2\": \"true\",\n",
    "        \"LANGCHAIN_ENDPOINT\": \"https://api.smith.langchain.com\",\n",
    "        \"LANGCHAIN_PROJECT\": \"07-EnumOutputParser\",\n",
    "    }\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4d32092",
   "metadata": {},
   "source": [
    "You can alternatively set ```OPENAI_API_KEY``` in ```.env``` file and load it. \n",
    "\n",
    "[Note] This is not necessary if you've already set ```OPENAI_API_KEY``` in previous steps."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fe07a67e",
   "metadata": {},
   "outputs": [],
   "source": [
    "from dotenv import load_dotenv\n",
    "\n",
    "load_dotenv(override=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a2387747",
   "metadata": {},
   "source": [
    "## Introduction to EnumOutputParser\n",
    "\n",
    "```EnumOutputParser``` is a tool that strictly parses an LLM's output into a defined enumeration (Enum).\n",
    "This ensures that the model output is always one of the enumerated values.\n",
    "\n",
    "**Use cases**\n",
    "- When you only want one valid choice from a set of possibilities.\n",
    "- When you want to avoid typos and variations by using a clear Enum value.\n",
    "\n",
    "In the following example, we define an ```Colors``` Enum and make the LLM return one of ```red/green/blue``` by parsing the output."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12adc8fd",
   "metadata": {},
   "source": [
    "## Example: Colors Enum Parser\n",
    "\n",
    "The code below shows how to define the ```Colors(Enum)``` class and wrap it with ```EnumOutputParser```, then integrate it into a prompt chain.\n",
    "Once the chain is executed, the LLM response is **strictly** parsed into one of the values in ```Colors```."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2ee6213d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import EnumOutputParser\n",
    "from langchain.output_parsers.enum import EnumOutputParser"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "95c0111c",
   "metadata": {},
   "source": [
    "Define the ```Colors``` enumeration using the ```Enum``` class from Python's built-in ```enum``` module."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0db99b4f",
   "metadata": {},
   "outputs": [],
   "source": [
    "from enum import Enum\n",
    "\n",
    "class Colors(Enum):\n",
    "    RED = \"Red\"\n",
    "    GREEN = \"Green\"\n",
    "    BLUE = \"Blue\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "07b6a4da",
   "metadata": {},
   "source": [
    "Now we create an ```EnumOutputParser``` object for parsing strings into the ```Colors``` enumeration."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "71ce0668",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Instantiate EnumOutputParser\n",
    "parser = EnumOutputParser(enum=Colors)\n",
    "\n",
    "# You can view the format instructions that the parser expects.\n",
    "print(parser.get_format_instructions())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2fabda65",
   "metadata": {},
   "source": [
    "Below is an example that constructs a simple chain using ```PromptTemplate``` and ```ChatOpenAI```.\n",
    "If the LLM responds about which color the object \"sky\" is, the parser will convert that string into a ```Colors``` value."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2e1f7dfc",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.prompts import PromptTemplate\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "# Prompt template: the parser's format instructions are added at the end.\n",
    "prompt = (\n",
    "    PromptTemplate.from_template(\n",
    "        \"\"\"Which color is this object?\n",
    "\n",
    "Object: {object}\n",
    "\n",
    "Instructions: {instructions}\"\"\"\n",
    "    ).partial(instructions=parser.get_format_instructions())\n",
    ")\n",
    "\n",
    "# Entire chain: (prompt) -> (LLM) -> (Enum Parser)\n",
    "chain = prompt | ChatOpenAI(temperature=0) | parser"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d6f5b3fa",
   "metadata": {},
   "source": [
    "Now let's run the chain."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3121c9eb",
   "metadata": {},
   "outputs": [],
   "source": [
    "response = chain.invoke({\"object\": \"sky\"})\n",
    "print(\"Parsed Enum:\", response)\n",
    "print(\"Raw Enum Value:\", response.value)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "python3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
